<?php

namespace Tests;

use Laravolt\Avatar\Avatar;
use Laravolt\Avatar\Concerns\ImageExport;
use PHPUnit\Framework\TestCase;

class ImageExportTest extends TestCase
{
    protected $avatar;

    protected function setUp(): void
    {
        parent::setUp();

        // Create a test avatar class with ImageExport trait
        $this->avatar = new class extends Avatar
        {
            use ImageExport;

            public function __construct()
            {
                $config = [
                    'width' => 256,
                    'height' => 256,
                    'fontSize' => 96,
                    'driver' => 'gd',
                ];
                parent::__construct($config);
            }
        };
    }

    public function test_export_formats_validation()
    {
        $validFormats = ['png', 'jpg', 'jpeg', 'webp'];

        foreach ($validFormats as $format) {
            $this->assertContains($format, $this->avatar->getExportFormats());
        }
    }

    public function test_invalid_format_throws_exception()
    {
        $this->expectException(\InvalidArgumentException::class);
        $this->expectExceptionMessage("Unsupported format 'bmp'. Supported formats: png, jpg, jpeg, webp");

        $reflection = new \ReflectionClass($this->avatar);
        $method = $reflection->getMethod('validateExportFormat');
        $method->setAccessible(true);
        $method->invoke($this->avatar, 'bmp');
    }

    public function test_get_default_export_options()
    {
        $reflection = new \ReflectionClass($this->avatar);
        $method = $reflection->getMethod('getDefaultExportOptions');
        $method->setAccessible(true);

        $pngOptions = $method->invoke($this->avatar, 'png');
        $this->assertEquals(95, $pngOptions['quality']);
        $this->assertEquals(6, $pngOptions['compression']);
        $this->assertFalse($pngOptions['interlaced']);

        $jpgOptions = $method->invoke($this->avatar, 'jpg');
        $this->assertEquals(90, $jpgOptions['quality']);
        $this->assertTrue($jpgOptions['progressive']);

        $webpOptions = $method->invoke($this->avatar, 'webp');
        $this->assertEquals(85, $webpOptions['quality']);
        $this->assertFalse($webpOptions['lossless']);
    }

    public function test_sanitize_filename()
    {
        $reflection = new \ReflectionClass($this->avatar);
        $method = $reflection->getMethod('sanitizeFilename');
        $method->setAccessible(true);

        // Test unsafe characters removal
        $unsafe = 'file/name\\with:unsafe*chars?"<>|';
        $safe = $method->invoke($this->avatar, $unsafe);
        $this->assertEquals('file_name_with_unsafe_chars', $safe);

        // Test multiple underscores reduction
        $multiple = 'file___with___multiple___underscores';
        $reduced = $method->invoke($this->avatar, $multiple);
        $this->assertEquals('file_with_multiple_underscores', $reduced);

        // Test length limiting
        $long = str_repeat('a', 150);
        $limited = $method->invoke($this->avatar, $long);
        $this->assertEquals(100, strlen($limited));
    }

    public function test_calculate_watermark_position()
    {
        $reflection = new \ReflectionClass($this->avatar);
        $method = $reflection->getMethod('calculateWatermarkPosition');
        $method->setAccessible(true);

        $positions = [
            'top-left' => [12, 36], // margin + fontSize (5% of 256 = 12.8, rounded down to 12)
            'top-right' => [256 - 12, 36],
            'bottom-left' => [12, 256 - 12],
            'bottom-right' => [256 - 12, 256 - 12],
            'center' => [128, 128],
        ];

        foreach ($positions as $position => $expected) {
            $result = $method->invoke($this->avatar, $position, 'Test', 24);
            $this->assertEquals($expected, $result, "Position {$position} calculation failed");
        }
    }

    public function test_estimate_file_sizes()
    {
        $reflection = new \ReflectionClass($this->avatar);
        $method = $reflection->getMethod('estimateFileSizes');
        $method->setAccessible(true);

        $estimates = $method->invoke($this->avatar);

        $this->assertArrayHasKey('png', $estimates);
        $this->assertArrayHasKey('jpg', $estimates);
        $this->assertArrayHasKey('webp', $estimates);

        // Estimates should contain byte information
        $this->assertStringContainsString('bytes', $estimates['png']);
        $this->assertStringContainsString('bytes', $estimates['jpg']);
        $this->assertStringContainsString('bytes', $estimates['webp']);
    }

    public function test_set_export_options()
    {
        $options = [
            'quality' => 95,
            'progressive' => true,
        ];

        $result = $this->avatar->setExportOptions($options);

        $this->assertInstanceOf(get_class($this->avatar), $result);
        $this->assertEquals($options, $this->avatar->getExportOptions());

        // Test merging options
        $additionalOptions = ['compression' => 8];
        $this->avatar->setExportOptions($additionalOptions);

        $expected = array_merge($options, $additionalOptions);
        $this->assertEquals($expected, $this->avatar->getExportOptions());
    }

    public function test_get_export_stats()
    {
        $stats = $this->avatar->getExportStats();

        $this->assertArrayHasKey('supported_formats', $stats);
        $this->assertArrayHasKey('current_options', $stats);
        $this->assertArrayHasKey('image_dimensions', $stats);
        $this->assertArrayHasKey('estimated_file_sizes', $stats);

        $this->assertEquals(['png', 'jpg', 'jpeg', 'webp'], $stats['supported_formats']);
        $this->assertEquals(256, $stats['image_dimensions']['width']);
        $this->assertEquals(256, $stats['image_dimensions']['height']);
    }

    public function test_apply_variation()
    {
        $originalBackground = $this->avatar->getBackground();
        $originalForeground = $this->avatar->getForeground();
        $originalShape = $this->avatar->getShape();

        $variation = [
            'background' => '#FF0000',
            'foreground' => '#00FF00',
            'shape' => 'square',
        ];

        $reflection = new \ReflectionClass($this->avatar);
        $method = $reflection->getMethod('applyVariation');
        $method->setAccessible(true);
        $method->invoke($this->avatar, $variation);

        $this->assertEquals('#FF0000', $this->avatar->getBackground());
        $this->assertEquals('#00FF00', $this->avatar->getForeground());
        $this->assertEquals('square', $this->avatar->getShape());
    }

    /**
     * Test that the ImageExport trait properly extends functionality
     */
    public function test_trait_integration()
    {
        $this->assertTrue(method_exists($this->avatar, 'exportImage'));
        $this->assertTrue(method_exists($this->avatar, 'exportResponsiveSizes'));
        $this->assertTrue(method_exists($this->avatar, 'bulkExport'));
        $this->assertTrue(method_exists($this->avatar, 'exportWithWatermark'));
        $this->assertTrue(method_exists($this->avatar, 'setExportOptions'));
        $this->assertTrue(method_exists($this->avatar, 'getExportStats'));
    }

    /**
     * Test responsive sizes export structure
     */
    public function test_responsive_sizes_structure()
    {
        $sizes = [
            'small' => ['width' => 64, 'height' => 64],
            'medium' => ['width' => 128, 'height' => 128],
            'large' => ['width' => 256, 'height' => 256, 'fontSize' => 96],
        ];

        // This test validates the structure without actually creating files
        foreach ($sizes as $name => $dimensions) {
            $this->assertArrayHasKey('width', $dimensions);
            $this->assertArrayHasKey('height', $dimensions);
            $this->assertIsInt($dimensions['width']);
            $this->assertIsInt($dimensions['height']);
        }
    }

    protected function tearDown(): void
    {
        parent::tearDown();
    }
}
